use alloc::{string::String, sync::Arc};
use core::hint::spin_loop;
use system_error::SystemError;

use crate::{
    arch::reboot::{machine_halt, machine_restart},
    driver::base::device::device_shutdown,
    init::initial_kthread::{set_system_state, SystemState},
    libs::{
        mutex::Mutex,
        notifier::{BlockingNotifierChain, NotifierBlock},
    },
    syscall::user_access::check_and_clone_cstr,
};

static SYSTEM_TRANSITION_MUTEX: Mutex<()> = Mutex::new(());

const LINUX_REBOOT_MAGIC1: u32 = 0xfee1dead;
const LINUX_REBOOT_MAGIC2: u32 = 672274793;
const LINUX_REBOOT_MAGIC2A: u32 = 85072278;
const LINUX_REBOOT_MAGIC2B: u32 = 369367448;
const LINUX_REBOOT_MAGIC2C: u32 = 537993216;

static mut C_A_D: bool = true;
lazy_static! {
    /// 注册此通知链的回调函数通常属于内核子系统或驱动程序
    static ref REBOOT_NOTIFIER_LIST: Mutex<BlockingNotifierChain<RebootNotifyEvent, String>> =
        Mutex::new(BlockingNotifierChain::new());
}
lazy_static! {
    /// 注册此通知链的回调函数通常是与硬件相关的重启准备处理程序
    static ref RESTART_PERP_HANDLER_LIST: Mutex<BlockingNotifierChain<RebootNotifyEvent, String>> =
        Mutex::new(BlockingNotifierChain::new());
}
lazy_static! {
    /// 注册此通知链的回调函数通常是与硬件相关的重启准备处理程序
    static ref POWER_OFF_PREP_HANDLER_LIST: Mutex<BlockingNotifierChain<RebootNotifyEvent, String>> =
        Mutex::new(BlockingNotifierChain::new());
}

/// # 功能
///
/// 将一个任意实现`NotifierBlock`trait的结构体notifier注册到`REBOOT_NOTIFIER_LIST`通知连中
#[allow(dead_code)]
pub fn register_reboot_notifier(
    notifier: Arc<dyn NotifierBlock<RebootNotifyEvent, String>>,
) -> Result<(), SystemError> {
    let mut reboot_notifier_list = REBOOT_NOTIFIER_LIST.lock();
    return reboot_notifier_list.register(notifier);
}

/// # 功能
///
/// 从`REBOOT_NOTIFIER_LIST`通知链中移除指定的实现`NotifierBlock`trait的结构体。
#[allow(dead_code)]
pub fn unregister_reboot_notifier(
    notifier: Arc<dyn NotifierBlock<RebootNotifyEvent, String>>,
) -> Result<(), SystemError> {
    let mut reboot_notifier_list = REBOOT_NOTIFIER_LIST.lock();
    return reboot_notifier_list.unregister(notifier);
}

#[derive(Debug)]
pub enum RebootCommand {
    /// 重启系统，使用默认命令和模式
    Restart,
    /// 停止操作系统，并将系统控制权交给ROM监视器（如果有）
    Halt,
    /// Ctrl-Alt-Del序列导致执行RESTART命令
    CadOn,
    /// Ctrl-Alt-Del序列向init任务发送SIGINT信号
    CadOff,
    /// 停止操作系统，如果可能的话从系统中移除所有电源
    PowerOff,
    /// 使用给定的命令字符串重启系统
    Restart2,
    /// 使用软件挂起（如果编译在内）挂起系统
    SoftwareSuspend,
    /// 使用预先加载的Linux内核重启系统
    Kexec,
}

impl TryFrom<u32> for RebootCommand {
    type Error = SystemError;

    fn try_from(value: u32) -> Result<Self, Self::Error> {
        match value {
            0x01234567 => Ok(RebootCommand::Restart),
            0xCDEF0123 => Ok(RebootCommand::Halt),
            0x89ABCDEF => Ok(RebootCommand::CadOn),
            0x00000000 => Ok(RebootCommand::CadOff),
            0x4321FEDC => Ok(RebootCommand::PowerOff),
            0xA1B2C3D4 => Ok(RebootCommand::Restart2),
            0xD000FCE2 => Ok(RebootCommand::SoftwareSuspend),
            0x45584543 => Ok(RebootCommand::Kexec),
            _ => Err(SystemError::EINVAL),
        }
    }
}

impl From<RebootCommand> for u32 {
    fn from(val: RebootCommand) -> Self {
        match val {
            RebootCommand::Restart => 0x01234567,
            RebootCommand::Halt => 0xCDEF0123,
            RebootCommand::CadOn => 0x89ABCDEF,
            RebootCommand::CadOff => 0x00000000,
            RebootCommand::PowerOff => 0x4321FEDC,
            RebootCommand::Restart2 => 0xA1B2C3D4,
            RebootCommand::SoftwareSuspend => 0xD000FCE2,
            RebootCommand::Kexec => 0x45584543,
        }
    }
}

#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
pub enum RebootNotifyEvent {
    /// 系统关闭
    Down,
    /// 系统重启
    Restart,
    /// 系统挂起
    Halt,
    /// 系统关闭电源
    PowerOff,
}

/// 系统调用reboot的实现
///
/// 参考：https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/reboot.c#700
pub(super) fn do_sys_reboot(
    magic1: u32,
    magic2: u32,
    cmd: u32,
    arg: usize,
) -> Result<(), SystemError> {
    if magic1 != LINUX_REBOOT_MAGIC1
        || (magic2 != LINUX_REBOOT_MAGIC2
            && magic2 != LINUX_REBOOT_MAGIC2A
            && magic2 != LINUX_REBOOT_MAGIC2B
            && magic2 != LINUX_REBOOT_MAGIC2C)
    {
        return Err(SystemError::EINVAL);
    }
    let command = RebootCommand::try_from(cmd)?;
    let _guard = SYSTEM_TRANSITION_MUTEX.lock();
    log::debug!(
        "do_sys_reboot: magic1={}, magic2={}, cmd={:?}",
        magic1,
        magic2,
        command
    );
    match command {
        RebootCommand::Restart => kernel_restart(None),
        RebootCommand::Halt => kernel_halt(),
        RebootCommand::CadOn => {
            unsafe {
                C_A_D = true;
            }
            return Ok(());
        }
        RebootCommand::CadOff => {
            unsafe {
                C_A_D = false;
            }
            return Ok(());
        }
        RebootCommand::PowerOff => kernel_power_off(),
        RebootCommand::Restart2 => {
            let s = check_and_clone_cstr(arg as *const u8, Some(256))?;
            let cmd_str = s.to_str().map_err(|_| SystemError::EINVAL)?;
            kernel_restart(Some(cmd_str));
        }
        RebootCommand::SoftwareSuspend => {
            log::warn!("do_sys_reboot: SoftwareSuspend not implemented");
            return Err(SystemError::ENOSYS);
        }
        RebootCommand::Kexec => {
            crate::init::kexec::kexec_core::kernel_kexec();
            return Ok(());
        }
    }
}

/// kernel_restart - 重启系统
///
/// ## 参数
/// - cmd: 指向包含重启命令的缓冲区的指针，或者 None
///
/// 关闭所有东西并执行一个干净的重启。
/// 在中断上下文中调用这是不安全的。
///
/// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/reboot.c#265
pub fn kernel_restart(cmd: Option<&str>) -> ! {
    kernel_restart_prepare(cmd);
    do_kernel_restart_prepare();

    if let Some(cmd) = cmd {
        log::warn!("Restarting system with command: '{}'", cmd);
    } else {
        log::warn!("Restarting system...");
    }

    // 执行与机器硬件相关的重启操作
    machine_restart(cmd);
}

/// # 功能
///
/// 处理一些重启前的准备工作
fn kernel_restart_prepare(cmd: Option<&str>) {
    let cmd = if let Some(cmd) = cmd {
        // 将&str转换为String
        String::from(cmd)
    } else {
        String::new()
    };
    REBOOT_NOTIFIER_LIST
        .lock()
        .call_chain(RebootNotifyEvent::Restart, Some(&cmd), None);

    set_system_state(SystemState::Restart);

    device_shutdown();
}

fn do_kernel_restart_prepare() {
    RESTART_PERP_HANDLER_LIST
        .lock()
        .call_chain(RebootNotifyEvent::Restart, None, None);
}

/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/reboot.c#678
pub fn kernel_power_off() -> ! {
    kernel_shutdown_prepare(SystemState::PowerOff);
    do_kernel_power_off_prepare();

    log::warn!("Power down");
    log::warn!("Currently, the system cannot be powered off, so we halt here.");
    loop {
        spin_loop();
    }
}

/// # 功能
///
/// 在系统关机前执行必要的准备工作
///
/// 参考: https://elixir.bootlin.com/linux/v6.6/source/kernel/reboot.c#L280
pub fn kernel_shutdown_prepare(state: SystemState) {
    let event = if state == SystemState::Halt {
        RebootNotifyEvent::Halt
    } else {
        RebootNotifyEvent::PowerOff
    };
    REBOOT_NOTIFIER_LIST.lock().call_chain(event, None, None);

    set_system_state(state);

    device_shutdown();
}

fn do_kernel_power_off_prepare() {
    POWER_OFF_PREP_HANDLER_LIST
        .lock()
        .call_chain(RebootNotifyEvent::PowerOff, None, None);
}

/// # 功能
///
/// 执行内核停止操作
///
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/reboot.c#293
pub fn kernel_halt() -> ! {
    kernel_shutdown_prepare(SystemState::Halt);

    machine_halt();
}
